﻿// ———————————————————————–
// <copyright file="DataService.svc.cs" company="The MITRE Corporation">
//    Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//    http://www.apache.org/licenses/LICENSE-2.0
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
// </copyright>
// ———————————————————————–
/////////////////////////////////////////////////////////////////////////////////////////////////
// DataService.svc.cs - "Description"
// Project: "ICNETSOA"- "ICNETRest"
//
// Language:    C#, .NET 4.0
// Platform:    Windows 7, VS 2010
// Author:      Don McGarry The MITRE Corporation
/////////////////////////////////////////////////////////////////////////////////////////////////

// Copyright (c) 2010 The MITRE Corporation. All rights reserved.
//
// NOTICE
// This software was produced for the U. S. Government
// under Contract No. FA8721-09-C-0001, and is
// subject to the Rights in Noncommercial Computer Software
// and Noncommercial Computer Software Documentation Clause
// (DFARS) 252.227-7014 (JUN 1995)

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Web;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Xml.Xsl;
using EDXLHistory;
using EDXLSharp.EDXLDELib;
using ICNETDAL;
using ICNETDAL.AWS;

namespace ICNETREST
{
  /// <summary>
  /// Methods for pulling information from the database, as well as converting it to HTML.
  /// </summary>
  [ServiceContract(Namespace = "urn:icnet:mitre:org:DataService")]

  // [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
  [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
  public class DataService
  {
    /// <summary>
    /// The IContentCache used to fetch content.
    /// </summary>
    private IContentCache ContentCache;

    public DataService()
      : base()
    {
      ContentCache = new DynamoContentCache();
    }

    public DataService(IContentCache contentCache)
      : base()
    {
      ContentCache = contentCache;
    }

    /// <summary>
    ///  Used for padding short error messages, which are not shown in some browsers if the message is under 512 bytes.
    /// </summary>
    private string lorem = "<!-- " + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris pellentesque rutrum tincidunt. " +
                                    "Proin mauris ante, dignissim Id elementum a, malesuada vel purus. Pellentesque est mi, sollicitudin " +
                                    "nec semper convallis, luctus ut tortor. Sed nec quam turpis. In hac habitasse platea dictumst. Proin " +
                                    " luctus turpis vel metus lobortis a eleifend neque rhoncus. Nam non laoreet libero. Sed cursus tincidunt" +
                                    " dui non vehicula. Nam sagittis ante nec magna feugiat facilisis. Etiam odio sem, vestibulum sed sed. " + " -->";

    /// <summary>
    /// The header of the HTTP message.
    /// </summary>
    private string httpHeaders = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                                 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"> ";

    /// <summary>
    /// Pulls the DE content out the database by referencing its hash value. 
    /// </summary>
    /// <param name="contentKeyStr">The hash value of the object. </param>
    /// <returns>The DE object</returns>
    [WebGet(UriTemplate = "XML/{ContentKeyStr}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare), OperationContract]
    public XElement GetXML(string contentKeyStr)
    {
      int hash;
      if (Int32.TryParse(contentKeyStr, out hash))
      {
        string xml = ContentCache.GetContentObjectByContentHash(hash);
        XElement xe = XElement.Parse(xml);
        return xe;
      }
      else
      {
        WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
        return null;
      }
    }

    /// <summary>
    /// Pulls the DE out the database by referencing DE Id and Sender 
    /// </summary>
    /// <param name="contentKeyStr">The hash value of the object. </param>
    /// <returns>The DE object</returns>
    [WebGet(UriTemplate = "DEXML?Id={IdStr}&Sender={Sender}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare), OperationContract]
    public XElement GetDEXML(string IdStr, string Sender)
    {

      if (String.IsNullOrWhiteSpace(IdStr) || String.IsNullOrWhiteSpace(Sender))
      {
        WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
        WebOperationContext.Current.OutgoingResponse.StatusDescription = "Either Distribution ID or Sender were NULL or Empty.";
        return null;
      }
      else
      {
        EDXLDEDal dal = new EDXLDEDal();
        XElement xe = dal.GetDE(IdStr, Sender);
        return xe;
      }
    }

    /// <summary>
    /// Transform the DE XML into HTML
    /// </summary>
    /// <param name="contentKeyStr">The string that corresponds to the content, in the form of a hash.</param>
    /// <returns>If the DE message is found, it is returned as HTML. If it is not found, or has no content, null is returned</returns>
    [WebGet(UriTemplate = "DEHTML?Id={IdStr}&Sender={Sender}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare), OperationContract]
    public Stream GetDEHTML(string IdStr, string Sender)
    {
      WebOperationContext.Current.OutgoingResponse.ContentType = "Text/html";
      System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();

      if (String.IsNullOrWhiteSpace(IdStr) || String.IsNullOrWhiteSpace(Sender))
      {
        WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
        return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Expected the Distribution Id and Sender at the end of the url.</BODY></HTML>" + this.lorem)) as Stream;
      }
      else
      {
        EDXLDEDal dal = new EDXLDEDal();
        XElement xe = dal.GetDE(IdStr, Sender);
        string DEXSLT = "XSLT\\HTML DE.xsl";

        try
        {
          //return new MemoryStream(encoding.GetBytes(httpHeaders + "<HTML><BODY> work in progress </BODY></HTML>" + this.lorem)) as Stream;
          return TransformDEXMLtoHTML(xe, DEXSLT);
        }
        catch (System.Exception e)
        {
          WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
          return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Failed to convert to html \"\"  : " + e.Message + "   ----    " +
              e.StackTrace + "    ------    " + e.InnerException + "             ----------------       " + e.Source.ToString() + "</BODY></HTML>" + this.lorem)) as Stream;
        }
      }
    }

    /// <summary>
    /// Transform the DE XML into HTML
    /// </summary>
    /// <param name="contentKeyStr">The string that corresponds to the content, in the form of a hash.</param>
    /// <returns>If the DE message is found, it is returned as HTML. If it is not found, or has no content, null is returned</returns>
    [WebGet(UriTemplate = "History/DEHTML?Id={IdStr}&Sender={Sender}&DateTime={DateTimeSent}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare), OperationContract]
    public Stream GetHistoryDEHTML(string IdStr, string Sender, string DateTimeSent)
    {
      WebOperationContext.Current.OutgoingResponse.ContentType = "Text/html";
      System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();

      if (String.IsNullOrWhiteSpace(IdStr) || String.IsNullOrWhiteSpace(Sender) || string.IsNullOrWhiteSpace(DateTimeSent))
      {
        WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
        return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Expected a Distribution Id, Sender, and DateTime at the end of the url.</BODY></HTML>" + this.lorem)) as Stream;
      }
      else
      {
        List<XElement> xeList = History.GetDE(IdStr, Sender, DateTimeSent);
        string DEXSLT = "XSLT\\HTML DE.xsl";

        try
        {
          if (xeList == null || xeList.Count == 0)
          {
            WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
            return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Requested resource not found.</BODY></HTML>" + this.lorem)) as Stream;
          }
          else
          {
            //return new MemoryStream(encoding.GetBytes(httpHeaders + "<HTML><BODY> work in progress </BODY></HTML>" + this.lorem)) as Stream;
            return TransformDEXMLtoHTML(xeList[0], DEXSLT);
          }
        }
        catch (System.Exception e)
        {
          WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
          return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Failed to convert to html \"\"  : " + e.Message + "   ----    " +
              e.StackTrace + "    ------    " + e.InnerException + "             ----------------       " + e.Source.ToString() + "</BODY></HTML>" + this.lorem)) as Stream;
        }
      }
    }

    /// <summary>
    /// Parses a URL to find the DE message that it is attempting to look up. 
    /// </summary>
    /// <param name="contentKeyStr">The key on the end of the URL that is used to locate the content</param>
    /// <returns>If the DE message is found, it is returned as XML. If it is not found, or has no content, null is returned. </returns>
    [WebGet(UriTemplate = "History/MIME?Id={IdStr}&Sender={Sender}&DateTime={DateTimeSent}&ContentDescription={ContentDescription}"), OperationContract]
    public Stream GetHistoryMIME(string IdStr, string Sender, string DateTimeSent, string ContentDescription)
    {
      System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();

      if (String.IsNullOrWhiteSpace(IdStr) || String.IsNullOrWhiteSpace(Sender) || string.IsNullOrWhiteSpace(DateTimeSent) || string.IsNullOrWhiteSpace(ContentDescription))
      {
        WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
        return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Expected a Distribution Id, Sender, DateTime, and ContentDescription at the end of the url.</BODY></HTML>" + this.lorem)) as Stream;
      }
      else
      {
        List<XElement> xeList = History.GetDE(IdStr, Sender, DateTimeSent);

        if (xeList == null || xeList.Count == 0)
        {
          WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
          return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Requested resource not found.</BODY></HTML>" + this.lorem)) as Stream;
        }
        else
        {
          EDXLDE de = new EDXLDE(xeList[0].ToString());

          NonXMLContentType nco = GetNonXMLContentObjectByDescription(de, ContentDescription);

          // if we didn't find the content
          if (nco == null)
          {
            WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
            return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Requested resource not found.</BODY></HTML>" + this.lorem)) as Stream;
          }
          else
          {
            byte[] content = Convert.FromBase64String(nco.ContentData);

            if (content == null || content.Length < 1)
            {
              WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
              return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Requested resource not found.</BODY></HTML>" + this.lorem)) as Stream;
            }
            else
            {
              MemoryStream ms = new MemoryStream(content);
              string contentType = nco.MIMEType;

              if (String.IsNullOrWhiteSpace(contentType))
              {
                contentType = "image/jpeg";
              }

              WebOperationContext.Current.OutgoingResponse.ContentType = contentType;
              return ms as Stream;
            }
          }
        }
      }
    }

    private NonXMLContentType GetNonXMLContentObjectByDescription(EDXLDE de, string ContentDescription)
    {
      NonXMLContentType nco = null;

      foreach (ContentObject co in de.ContentObjects)
      {
        if (co.ContentDescription.Equals(ContentDescription))
        {
          nco = co.NonXMLContent;
        }
      }

      return nco;
    }


    // Dummy callback used by 'GetThumbnail' below.
    private bool ThumbnailCallback()
    {
      return false;
    }

    /// <summary>
    /// Returns a thumbnail for a given ContentKeyStr. (In the future it should generates it if needed, otherwise returns a cached copy from the filesystem)
    /// </summary>
    /// <param name="contentKeyStr">The key on the end of the URL that is used to locate the content</param>
    /// <returns>A stream of bytes that is a jpg image </returns>
    [WebGet(UriTemplate = "Thumbnail/{ContentKeyStr}?height={thumbnailHeightStr}"), OperationContract]
    public Stream GetThumbnail(string contentKeyStr, string thumbnailHeightStr)
    {
      int hash;
      int thumbnailHeight;
      bool canParseKey = Int32.TryParse(contentKeyStr, out hash);
      bool canParseHeight = Int32.TryParse(thumbnailHeightStr, out thumbnailHeight);

      if (!(canParseKey && canParseHeight))
      {
        System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
        WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
        return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Bad params</BODY></HTML>" + this.lorem)) as Stream;
      }
      else
      {
        EDXLDEDal dal = new EDXLDEDal();
        byte[] content = dal.GetNonXMLContentObjectByHash(hash);

        // if we didn't find the content
        if (content == null || content.Length < 1)
        {
          System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
          WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
          return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>The key on the end of the url (" + contentKeyStr + ") is not available. The key is used to lookup a message. You may be seeing this error because the key is for an expired message. Check the feed for an updated link.</BODY></HTML>" + this.lorem)) as Stream;
        }
        else
        {
          //MemoryStream ms = new MemoryStream(content);
          string contentType = dal.GetNonXMLMIMETypeByHash(hash);
          if (!contentType.Contains("image"))
          {
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
            WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
            return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>The key on the end of the url (" + contentKeyStr + ") does not link to an image, so no thumbnail is available</BODY></HTML>" + this.lorem)) as Stream;
          }


          // Convert byte[] to Image
          MemoryStream readerStream = new MemoryStream();
          readerStream.Write(content, 0, content.Length);
          Image image = Image.FromStream(readerStream, true);



          MemoryStream outputStream = new MemoryStream();
          Image.GetThumbnailImageAbort thumbnailCallback = new Image.GetThumbnailImageAbort(ThumbnailCallback);
          int thumbnailWidth = (int)((double)image.Width * ((double)thumbnailHeight / (double)image.Height));
          Image thumbnail = image.GetThumbnailImage(thumbnailWidth, thumbnailHeight, thumbnailCallback, IntPtr.Zero);

          thumbnail.Save(outputStream, System.Drawing.Imaging.ImageFormat.Jpeg);

          outputStream.Position = 0;
          WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
          return outputStream as Stream;
        }
      }
    }
    
    /// <summary>
    /// Parses a URL to find the DE message that it is attempting to look up. 
    /// </summary>
    /// <param name="contentKeyStr">The key on the end of the URL that is used to locate the content</param>
    /// <returns>If the DE message is found, it is returned as XML. If it is not found, or has no content, null is returned. </returns>
    [WebGet(UriTemplate = "MIME/{ContentKeyStr}"), OperationContract]
    public Stream GetMIME(string contentKeyStr)
    {
      int hash;
      bool canParse = Int32.TryParse(contentKeyStr, out hash);

      if (!canParse)
      {
        System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
        WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
        return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>Expected a 32 bit signed integer at the end of the url. You provided (" + contentKeyStr + "), which is not parsable as an integer.</BODY></HTML>" + this.lorem)) as Stream;
      }
      else
      {
        EDXLDEDal dal = new EDXLDEDal();
        byte[] content = dal.GetNonXMLContentObjectByHash(hash);

        // if we didn't find the content
        if (content == null || content.Length < 1)
        {
          System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
          WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
          return new MemoryStream(encoding.GetBytes(this.httpHeaders + "<HTML><BODY>The key on the end of the url (" + contentKeyStr + ") is not available. The key is used to lookup a message. You may be seeing this error because the key is for an expired message. Check the feed for an updated link.</BODY></HTML>" + this.lorem)) as Stream;
        }
        else
        {
          MemoryStream ms = new MemoryStream(content);
          string contentType = dal.GetNonXMLMIMETypeByHash(hash);
          if (String.IsNullOrWhiteSpace(contentType))
          {
            contentType = "image/jpeg";
          }

          WebOperationContext.Current.OutgoingResponse.ContentType = contentType;
          return ms as Stream;
        }
      }
    }

    /// <summary>
    /// Parses a URL to find the DE content that it is attempting to look up. 
    /// </summary>
    /// <param name="contentKeyStr">The string that corresponds to the content, in the form of a hash.</param>
    /// <returns>If the DE message is found, it is returned as HTML. If it is not found, or has no content, null is returned</returns>
    [WebGet(UriTemplate = "HTML/{ContentKeyStr}", ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare), OperationContract]
    public Stream GetHTML(string contentKeyStr)
    {
      WebOperationContext.Current.OutgoingResponse.ContentType = "text/html; charset=utf-8";
      int hash;
      System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();

      if (!Int32.TryParse(contentKeyStr, out hash))
      {
        WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.BadRequest;
        return new MemoryStream(Encoding.UTF8.GetBytes("<HTML><BODY>Expected a 32 bit signed integer at the end of the url. You provided (" + contentKeyStr + "), which is not parsable as an integer.</BODY></HTML>" + this.lorem));
      }

      try
      {
        string htmlContent = this.ContentCache.GetHTMLByContentHash(hash);

        if (!String.IsNullOrEmpty(htmlContent))
        {
          WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
          return new MemoryStream(Encoding.UTF8.GetBytes(htmlContent));
        }
        else
        {
          WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.NotFound;
          return new MemoryStream(Encoding.UTF8.GetBytes("<html><body>No content with this key was found.</body></html>"));
        }
      }
      catch (System.Exception e)
      {
        WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.InternalServerError;
        return new MemoryStream(Encoding.UTF8.GetBytes("<HTML><BODY>Failed to fetch html: " + e.Message + "   ----    " +
            e.StackTrace + "    ------    " + e.InnerException + "             ----------------       " + e.Source.ToString() + "</BODY></HTML>" + this.lorem));
      }

    }
    
    /// <summary>
    /// Transforms a DE object in XML format into HTML.
    /// </summary>
    /// <param name="xe">The XML object to be transformed.</param>
    /// <param name="type">The type of DE message that is being passed in.</param>
    /// <returns>The stream containing the converted html</returns>
    private static Stream TransformDEXMLtoHTML(XElement xe, string xsltFile)
    {
      // Create the Stream to place the output.
      System.IO.Stream str = new System.IO.MemoryStream();

      // Use .net XSLT libraries to conver the message XML to nice HTML
      System.Xml.Xsl.XslCompiledTransform xslt = new System.Xml.Xsl.XslCompiledTransform();
      XsltSettings xslt_settings = new XsltSettings();
      xslt_settings.EnableScript = true;
      xslt_settings.EnableDocumentFunction = true;

      XmlResolver resolver = new XmlUrlResolver();
      //resolver.Credentials = CredentialCache.DefaultCredentials;

      // Create an XsltArgumentList.
      XsltArgumentList xslArg = new XsltArgumentList();

      // Add an object to calculate the new book price.
      XsltFunctions obj = new XsltFunctions();
      xslArg.AddExtensionObject("http://csharp.org", obj);

      xslt.Load(HttpRuntime.AppDomainAppPath + xsltFile, xslt_settings, resolver);

      xslt.Transform(new XPathDocument(xe.CreateReader()), xslArg, str);

      // Remember to Flush the Stream and set the position to 0
      str.Flush();
      str.Position = 0;
      return str as Stream;
    }
  }

  public class XsltFunctions
  {
    public string GetAddressFromLatLon(string lat, string lon)
    {
      // if either is null, then assume we have nothing
      if (lat == null || lon == null)
      {
        lat = "0.0";
        lon = "0.0";
      }

      // this is the default string to send if we don't find a legit address
      string address = string.Format("Lat, Lon: {0}, {1}", lat, lon);

      try
      {
        // build the url to get the address from Google Geocoder
        string url = string.Format("http://maps.googleapis.com/maps/api/geocode/xml?latlng={0},{1}&sensor=false", lat, lon);

        XmlUrlResolver resolver = new XmlUrlResolver();
        resolver.Credentials = CredentialCache.DefaultCredentials;

        // parse the XML
        XmlDocument doc = new XmlDocument();
        doc.XmlResolver = resolver;
        doc.Load(url);

        // Make sure the status of the response is "OK"
        XmlNode statusNode = doc.SelectSingleNode("//GeocodeResponse/status");
        if (statusNode != null)
        {
          string status = statusNode.InnerText;
          if (string.Compare(status, "ok", true) == 0)
          {
            // Loop through the results
            XmlNodeList resultNodes = doc.SelectNodes("//GeocodeResponse/result");
            foreach (XmlNode resultNode in resultNodes)
            {
              XmlNode typeNode = resultNode.SelectSingleNode("type");
              if (typeNode != null)
              {
                // If the result type is a street address
                string type = typeNode.InnerText;
                if (string.Compare(type, "street_address", true) == 0 || string.Compare(type, "route", true) == 0)
                {
                  XmlNode addrNode = resultNode.SelectSingleNode("formatted_address");
                  if (addrNode != null)
                  {
                    // use the address given
                    address = addrNode.InnerText;
                    break;
                  }
                }
              }
            }
          }
        }
      }
      catch (Exception)
      {
        // do nothing 
      }
      return address;
    }
  }
}